/* COPYRIGHT_CHUNFENG */
#include "cf_list_file.h"
#include "cf_std.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef _WIN32_
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#include "lcf_log.h"

CFListHead* cf_list_file_new(const char* filePath, CFLineItemParseFunc lineParsefunc)
{
#ifdef _WIN32_
    HANDLE fHndl;
    HANDLE mHndl;
#else
	int fd;
#endif
	int length, parsed;
	struct stat dummyStat;
	char *start, *line;
	CFListHead *newNode = NULL, *retNode = NULL;
	
#ifdef _WIN32_
    fHndl = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, 
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(INVALID_HANDLE_VALUE == fHndl){
        return NULL;
    }
#else
	fd=open(filePath, O_RDONLY);
	if(fd == -1) {
		return NULL;
	}
#endif
	if(-1 == stat(filePath, &dummyStat)){
		goto ERR_CLOSE_FD;
	}
	length = dummyStat.st_size;
#ifdef _WIN32_
    mHndl = CreateFileMapping(fHndl, 0, PAGE_READONLY, 0,
            0, NULL);
    if(INVALID_HANDLE_VALUE == mHndl){
        goto ERR_CLOSE_FD;
    }
    start = MapViewOfFile(mHndl, FILE_MAP_READ, 0, 0, 0);
    if(!start){
        goto ERR_CLOSE_M;
    }
#else
	if(NULL == (start = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0))){
		goto ERR_CLOSE_FD;
	}
#endif
	parsed = 0;
	line = start;
	//int i=0;
	while(line != start + length){
	//i++;
	//printf("%d\n", i);
		char *end_n, *end;
		end_n = memchr(line, '\n', length - parsed);
		if(end_n) end = end_n;
		else end = start + length -1;
		//printf("end_n exists end_n =%d, end=%d\n", end_n , end);
        
        newNode = lineParsefunc(line, end);
        if(newNode){
            if(!retNode){
                    retNode = newNode;
                }else{
                    cf_list_insert_pre(retNode, newNode);
                }
        }

		if(end_n == NULL) break;
		line = end_n +1;
		parsed = end_n - start +1;
	}
#ifdef _WIN32_
    UnmapViewOfFile(start);
    CloseHandle(mHndl);
    CloseHandle(fHndl);
#else
	munmap(start, length);
	close(fd);
#endif
	return retNode;

#ifdef _WIN32_
ERR_CLOSE_M:
    CloseHandle(mHndl);
ERR_CLOSE_FD:
    CloseHandle(fHndl);
#else
ERR_CLOSE_FD:
    close(fd);
#endif
    return NULL;
}

void cf_list_file_free(CFListHead* head, CFLineItemFreeFunc freeFunc)
{
    CFListForeachSafe(head, node){
        freeFunc(node);
    }
}

int cf_list_file_write(CFListHead* head, int fd, CFLineItemWriteFunc lineItemWriteFunc)
{
	int writed = 0;
	//int i=0;
	LCF_DBG("\n");
	CFListForeach(head, node){
		//i++;
		//printf("%d\n", i);
		int tmpWrited;
		
		tmpWrited = lineItemWriteFunc(node, fd);
		if(-1 == tmpWrited) 
			return -1;
		else 
			writed += tmpWrited;
		tmpWrited = write(fd, "\n", 1);
		if(-1 == tmpWrited) 
			return -1;
		else 
			writed += tmpWrited;
	};
	return writed;
}


int cf_list_file_save(CFListHead* file, const char* filePath, CFLineItemWriteFunc lineItemWriteFunc)
{
    int fd;
	int res;
    fd = open(filePath, O_WRONLY|O_TRUNC);
    if(fd == -1){
        perror("open list file failed");
        return -1;
    }
    res = cf_list_file_write(file, fd, lineItemWriteFunc);
	close(fd);
	return res;
}
